package com.jackstraw.jack_base.datasource.common.entity;

import com.jackstraw.jack_base.datasource.common.entity.enums.DataSourceTypeEnum;
import com.jackstraw.jack_base.util.CollectionUtil;
import com.jackstraw.jack_base.util.ObjectUtil;
import com.jackstraw.jack_base.util.StringUtil;
import com.jackstraw.jack_base.util.entity.BaseEntity;
import com.jackstraw.jack_base.util.exception.BadConfigException;
import com.jackstraw.jack_base.util.exception.BadException;
import com.jackstraw.jack_base.util.exception.enums.ExceptionEnum;
import com.jackstraw.jack_base.util.tenant.entity.Tenant;
import com.jackstraw.jack_base.util.tenant.entity.enums.TenantSchemaEnum;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 主配置
 */
@Data
@Slf4j
public class Properties<PE extends AbstractPropertiesEntity<PE>> extends BaseEntity<Properties<PE>> {

    /**
     * 数据源类型
     */
    private DataSourceTypeEnum dataSourceTypeEnum;


    /**
     * 单租户下配置 or 多租户下主租户配置
     */
    private PropertiesTenantEntity<PE> propertiesTenantEntity;

    /**
     * 多租户下其余租户配置
     * <p>
     * 单租户下，此项为空
     */
    private Map<String, PropertiesTenantEntity<PE>> propertiesTenantEntityMap;


    /**
     * 总的租户配置数据
     */
    private Map<String, PropertiesTenantEntity<PE>> allPropertiesTenantEntityMap;


    /**
     * 默认数据源名称
     */
    private String defaultMainDataSourceName;


    /**
     * 租户名称集合
     */
    private final Set<String> tenantNameSet = new HashSet<>();


    /**
     * 数据源名称集合
     */
    private final Set<String> dataSourceNameSet = new HashSet<>();

    /**
     * 校验并解析
     */
    public void checkAndResolve(Tenant tenant) {
        if (ObjectUtil.ObjectUtilByLang3.isEmpty(this.dataSourceTypeEnum)) {
            log.error("数据源类型不能为空");
            throw new BadConfigException(BadException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "001"),
                    "数据源类型不能为空");
        }

        TenantSchemaEnum tenantSchemaEnum = tenant.getTenantSchemaEnum();


        if (ObjectUtil.ObjectUtilByLang3.isEmpty(this.propertiesTenantEntity)) {
            log.error("数据源类型为:[{}]的主租户配置为空", dataSourceTypeEnum.name());
            throw new BadConfigException(BadConfigException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "002")
                    , "数据源类型为:[{}]的主租户配置为空", dataSourceTypeEnum.name());
        }

        String tenantName = this.propertiesTenantEntity.getTenantName();

        if (!StringUtil.StringUtilsBylang3.equals(tenant.getDefaultTenantName(), tenantName)) {
            log.error("数据源类型为:[{}]的主租户名称异常", dataSourceTypeEnum.name());
            throw new BadConfigException(BadConfigException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "003")
                    , "数据源类型为:[{}]的主租户名称异常", dataSourceTypeEnum.name());
        }

        //解析主租户配置
        this.propertiesTenantEntity.checkAndResolve(dataSourceTypeEnum, this.tenantNameSet, this.dataSourceNameSet);

        //设置主数据源名称
        this.defaultMainDataSourceName = this.propertiesTenantEntity.getMainDataSourceName();

        //将租户配置添加至总租户配置集合中
        this.allPropertiesTenantEntityMap = new HashMap<>();

        this.allPropertiesTenantEntityMap.put(tenantName, this.propertiesTenantEntity);


        if (TenantSchemaEnum.more.equals(tenantSchemaEnum)) {
            //说明是多租户配置
            if (CollectionUtil.MapUtil.isEmpty(this.propertiesTenantEntityMap)) {
                log.error("当前为多租户模式，数据源类型为:[{}]的租户没有配置，多数据源配置不存在", dataSourceTypeEnum.name());
                throw new BadConfigException(BadConfigException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "004")
                        , "当前为多租户模式，数据源类型为:[{}]的租户没有配置，多数据源配置不存在", dataSourceTypeEnum.name());
            }
            this.propertiesTenantEntityMap.keySet().stream().forEach(otherTenantName -> {
                PropertiesTenantEntity<PE> tenantPropertiesEntity = this.propertiesTenantEntityMap.get(otherTenantName);
                tenantPropertiesEntity.setTenantName(otherTenantName);
                tenantPropertiesEntity.checkAndResolve(dataSourceTypeEnum, this.tenantNameSet, this.dataSourceNameSet);
                //获取每个租户下主数据源名称
                String mainDataSourceName = tenantPropertiesEntity.getMainDataSourceName();
                //要求每个租户下主数据源名称必须一致
                if (!this.defaultMainDataSourceName.equals(mainDataSourceName)) {
                    log.error("当前为多租户模式，数据源类型为:[{}]中租户[{}]的主数据员名称与主租户不一致", dataSourceTypeEnum.name(), otherTenantName);
                    throw new BadConfigException(BadConfigException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "014")
                            , "当前为多租户模式，数据源类型为:[{}]中租户[{}]的主数据员名称与主租户不一致", dataSourceTypeEnum.name(), otherTenantName);
                }
                this.allPropertiesTenantEntityMap.put(otherTenantName, tenantPropertiesEntity);
            });

        }
    }


}
